package service

import (
	"bufio"
	"encoding/json"
	"fmt"
	"gitee.com/kudingc/role_proxy/common"
	"gitee.com/kudingc/role_proxy/models"
	"io"
	"net"
)

// 微服务注册

// ListenAndServe 监听tcp服务
func ListenAndServe(address string) {
	// 清空数据库中的注册信息
	models.MicroserviceClear()

	// 绑定监听地址
	listener, err := net.Listen("tcp", address)
	if err != nil {
		common.ZhLogger.Fatal(fmt.Sprintf("listen err: %v", err))
	}
	defer listener.Close()
	common.ZhLogger.Info(fmt.Sprintf("bind: %s, start listening...", address))
	for {
		// Accept 会一直阻塞直到有新的连接建立或者listen中断才会返回
		conn, err := listener.Accept()
		if err != nil {
			// 通常是由于listener被关闭无法继续监听导致的错误
			common.ZhLogger.Fatal(fmt.Sprintf("accept err: %v", err))
		}
		// 开启新的 goroutine 处理该连接
		go Handle(conn)
	}
}

// Handle 客户端连接处理程序
func Handle(conn net.Conn) {
	common.ZhLogger.Info("start connection", conn.RemoteAddr())
	// 使用 bufio 标准库提供的缓冲区功能
	reader := bufio.NewReader(conn)
	for {
		var microService models.MicroService
		// ReadString 会一直阻塞直到遇到分隔符 \'\\n\'
		// 遇到分隔符后会返回上次遇到分隔符或连接建立后收到的所有数据, 包括分隔符本身
		// 若在遇到分隔符之前遇到异常, ReadString 会返回已收到的数据和错误信息
		msg, err := reader.ReadString('\n')
		if err != nil {
			// 通常遇到的错误是连接中断或被关闭，用io.EOF表示
			if err == io.EOF {
				common.ZhLogger.Info("connection close", conn.RemoteAddr())
			} else {
				common.ZhLogger.Error(err)
			}
			microService.UnRegisterMicroservice(conn)
			return
		}
		common.ZhLogger.Info("get data", msg)
		// 在这里进行服务注册操作，将微服务注册信息，在线状态写到缓存中，并同步更新到mysql中
		// 微服务信息必须包含的内容，服务id，服务code，服务副本id，服务IP及端口
		err = json.Unmarshal([]byte(msg), &microService)
		if err != nil || microService.Code == "" || microService.Id == 0 || microService.ServiceAddr == "" {
			if microService.CopyNum == "" {
				microService.CopyNum = "0"
			}
			conn.Write([]byte(common.ZhLogger.Info("failed to parse parameter data!\n")))
			continue
		}

		// 将注册状态更新到数据库中
		err = microService.RegisterMicroservice(conn)
		if err != nil {
			conn.Write([]byte(common.ZhLogger.Info("database write error, failed to register service!\n")))
			continue
		}

		// 将收到的信息发送给客户端
		conn.Write([]byte("register success!\n"))
	}
}
